In [1]:
%matplotlib inline
Depois de ter feito a análise do site (post aqui) e de ter feito um scraping dos dados do site da Comixology (post aqui), agora vamos fazer uma bela análise de dados das informações de comics digitais com Python (Pandas).
Vamos descobrir quais editoras tem os melhores preços relativos à quantidade de páginas de seus comics, as editoras com as melhores avaliações médias, além de uma análise mais profunda do duelo das gigantes: Marvel x DC Comics. Vamos começar.
Primeiro, como de costume, vamos importar os pacotes que iremos utilizar. O pacote warnings, serve somente para desligar possíveis avisos relativos à este código no notebook, para que o código não fique extenso. Os outros pacotes já são velhos conhecidos: numpy, pandas, matplotlib e seaborn.
In [2]:
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
comixology_df = pd.read_csv("comixology_comics_dataset_19.04.2016.csv", encoding = "ISO-8859-1")
Agora, vamos criar uma coluna de preço por página. Desta forma, podemos comparar preços de uma forma mais adequada, visto que o preço de um comic pode variar muito de acordo com suas páginas.
Para alguns comics, a informação de quantidade de páginas não existe, e desta forma, estes retornam um valor de infinito (inf) ao fazer o cálculo. Para estes, vamos definir seu valor como NaN:
In [3]:
# Vamos criar uma coluna de preço por página para futuras análises
comixology_df['Price_per_page'] = pd.Series(comixology_df['Original_price'] /
comixology_df['Page Count'],
index=comixology_df.index)
# Como alguns comics estão com a contagem de páginas igual a zero, vamos
# definir para estes o Price_per_page igual a NaN
comixology_df.Price_per_page[comixology_df['Price_per_page'] == np.inf] = np.nan
Vamos agora usar a função iterrows() do Dataframe para extrair o ano de publicação da versão impressa do comic. Esta função cria uma espécie de forloop, que itera sobre cada linha do DataFrame. Vamos usar o split para dividir a string que contém a data de publicação em uma lista. O terceiro valor será o ano. Em alguns casos, o ano retorna um valor maior que 2016. Como isto é impossível, estes valores também serão definidos como NaN:
In [4]:
# Vamos extrair o ano da string de data de publicação da versão impressa
print_dates = []
for index, row in comixology_df.iterrows():
if type(comixology_df.ix[index]['Print Release Date']) == float:
row_year = np.nan
else:
row_year = int(comixology_df.ix[index]['Print Release Date'].split()[2])
if row_year > 2016:
row_year = np.nan
print_dates.append(row_year)
comixology_df['Print_Release_Year'] = pd.Series(print_dates,
index=comixology_df.index)
In [5]:
# Algumas informações médias do site
average_price = np.nanmean(comixology_df['Original_price'])
average_page_count = np.nanmean(comixology_df['Page Count'])
average_rating = np.nanmean(comixology_df['Rating'])
average_rating_quantity = np.nanmean(comixology_df['Ratings_Quantity'])
average_price_per_page = np.nanmean(comixology_df['Price_per_page'])
print("Preço médio: " + str(average_price))
print("Quantidade média de páginas: " + str(average_page_count))
print("Avaliação média: " + str(average_rating))
print("Quantidade média de avaliações por comic: " +
str(average_rating_quantity))
print("Preço por página médio por comic: " + str(average_price_per_page))
Agora, definiremos o número máximo de colunas de cada campo para impressão da tabela em 40 colunas. Faremos isto pois o nome de alguns comics é bastante extenso, e a impressão da tabela ficaria bem esquisita. Desta forma, pelo menos conseguimos ver algumas informações a mais.
Depois vamos listar as comics que possuem 5 estrelas, possuem mais de 20 avaliações (para captar apenas as mais representativas; comics com 5 de avaliação média mas que possuam apenas uma avaliação podem não ser uma métrica muito boa) e vamos ordena-las por preço por página. No topo teremos algumas comics que são gratuitas (as 6 primeiras). Depois, temos ótimas comics, na visão dos usuários, com um preço por página bem atrativo.
In [6]:
# Definir o número de colunas para impressão de tabelas
pd.set_option('display.max_colwidth', 40)
In [7]:
# Vamos listar as comics com rating 5 estrelas que possuam pelo menos 20 ratings
# e ordena-las por preço por página
comics_with_5_stars = comixology_df[comixology_df.Rating == 5]
comics_with_5_stars = comics_with_5_stars[comics_with_5_stars.
Ratings_Quantity > 20]
print(comics_with_5_stars[['Name','Publisher','Price_per_page']].
sort_values(by='Price_per_page'))
Na próxima análise, usaremos apenas comics com mais de 5 avaliações. Para isso, vamos filtrar:
In [8]:
# Para a próxima análise, usaremos somente comics com mais de 5 ratings
comics_more_than_5_ratings = comixology_df[comixology_df.Ratings_Quantity > 5]
Vamos criar uma pivot table do Pandas, para visualizarmos a quantidade de comics com avaliação e a avaliação média deste Publisher. Depois vamos considerar como Publishers representativas aquelas que possuem pelo menos 20 comics com avaliações. Para isso faremos o filtro da pivot table. Depois, vamos ordenar esta tabela filtrada por avaliação média, em ordem decrescente. Ou seja, as primeiras Publishers são consideradas as que possuem a melhor avaliação média de seus comics. Repare que as gigantes DC Comics e Marvel ficam razoavelmente para baixo da lista.
In [9]:
# Criar pivot table com média das avaliações por Publisher
publishers_avg_rating = pd.pivot_table(comics_more_than_5_ratings,
values=['Rating'],
index=['Publisher'],
aggfunc=[np.mean, np.count_nonzero])
In [10]:
# Primeiramente vamos avaliar qualquer publisher que tenha mais de 20 comics
# com avaliações
main_pub_avg_rating = publishers_avg_rating[publishers_avg_rating.
count_nonzero.Rating > 20]
main_pub_avg_rating = main_pub_avg_rating.sort_values(by=('mean','Rating'),
ascending=False)
print(main_pub_avg_rating)
Para ajudar na visão, um gráfico em matplotlib que representa a tabela acima:
In [11]:
# Agora, um gráfico com a avaliação média de cada editora
y_axis = main_pub_avg_rating['mean']['Rating']
x_axis = range(len(y_axis))
plt.figure(figsize=(10, 6))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis, tuple(main_pub_avg_rating.index),rotation=90)
plt.show()
Para simplificar um pouco e ter uma tabela e gráfico mais fáceis de visualizar, vamos considerar agora comics que possuem pelo menos 300 comics com avaliações. Logo abaixo, o gráfico que representa a tabela (menos poluído e permitindo uma visão melhor da situação das publishers)
In [12]:
# E agora vamos ver as bem grandes, com mais de 300 comics com avaliações
big_pub_avg_rating = publishers_avg_rating[publishers_avg_rating.
count_nonzero.Rating > 300]
big_pub_avg_rating = big_pub_avg_rating.sort_values(by=('mean','Rating'),
ascending=False)
print(big_pub_avg_rating)
In [13]:
# E agora, o mesmo gráfico com a avaliação média das grandes editoras
y_axis = big_pub_avg_rating['mean']['Rating']
x_axis = np.arange(len(y_axis))
plt.figure(figsize=(10, 6))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.5, tuple(big_pub_avg_rating.index), rotation=90)
plt.show()
Uma coisa que eu acreditava que fosse legal de conferir era se a classificação etária faz alguma diferença na avaliação que os usuários dão a cada comic. Será que comics voltados para o público adulto possuem avaliações melhores? Ou ao contrário? Vamos checar fazendo uma nova pivot table:
In [14]:
# Vamos ver agora se a classificação etária faz alguma diferença significativa
# nas avaliações
rating_by_age = pd.pivot_table(comics_more_than_5_ratings,
values=['Rating'],
index=['Age Rating'],
aggfunc=[np.mean, np.count_nonzero])
print(rating_by_age)
In [15]:
# Gráfico de barras com a avaliação média por faixa etária
y_axis = rating_by_age['mean']['Rating']
x_axis = np.arange(len(y_axis))
plt.figure(figsize=(10, 6))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.25, tuple(rating_by_age.index), rotation=45)
plt.show()
Como podemos perceber, as barras do gráfico ficam com alturas bem próximas. Ao que parece, a classificação etária não afeta muito significativamente a avaliação dos comics. Se formos analisar apenas matematicamente, as comics liberadas para qualquer idade ou para maiores de 9 anos possuem as melhores avaliações.
Nosso próximo passo é ver como, de certa forma, evoluiu o número de lançamentos de quadrinhos (considerando as versões impressas) ao longo dos anos. Lembrando que já criamos a coluna com o ano de lançamento da versão impressa de um comic. O próximo passo é basicamente contar a quantidade de cada ano nesta coluna que criamos. Vamos fazer uma lista com os anos de lançamento passados para inteiros para que o eixo do gráfico faça a leitura correta:
In [16]:
# Cria tabela com a quantidade de quadrinhos lançados por ano, baseado na data
# de lançamento da versão impressa
print_releases_per_year = pd.pivot_table(comixology_df,
values=['Name'],
index=['Print_Release_Year'],
aggfunc=[np.count_nonzero])
print_years = []
for index, row in print_releases_per_year.iterrows():
print_year = int(index)
print_years.append(print_year)
print_releases_per_year.index = print_years
print(print_releases_per_year)
In [17]:
y_axis = print_releases_per_year['count_nonzero']['Name']
x_axis = print_releases_per_year['count_nonzero']['Name'].index
plt.figure(figsize=(10, 6))
plt.plot(x_axis, y_axis)
plt.show()
Os números mostram que o crescimento era moderado, até que na década de 2000 ocorreu um boom, com um crescimento bastante considerável até 2012, quando a quantidade de lançamentos começou a oscilar. A queda mostrada no ano de 2016 ocorre, obviamente, pois ainda estamos na metade do mesmo.
Agora, para fazer uma avaliação dos comics mais baixados no site (não dá para aferir os mais comprados, visto que alguns dos comics são gratuitos). Para esta análise, vamos ver quais são os 30 comics com mais avaliações.
In [18]:
# Vejamos agora as 30 comics com mais avaliações; se for mantida a proporção,
# pode-se dizer que estas são as comics mais baixadas (e não vendidas, pois
# algumas destas são gratuitas)
comics_by_ratings_quantity = comixology_df[['Name','Publisher',
'Ratings_Quantity']].sort_values(
by='Ratings_Quantity',
ascending=False)
print(comics_by_ratings_quantity.head(30))
In [19]:
y_axis = comics_by_ratings_quantity.head(30)['Ratings_Quantity']
x_axis = np.arange(len(y_axis))
plt.figure(figsize=(10, 6))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.5, tuple(comics_by_ratings_quantity.head(30)['Name']),
rotation=90)
plt.show()
Walking Dead liderando com (muuuita) folga. Depois, algumas comics de Marvel e DC e mais alguns comics variados.
Agora, vamos fazer uma análise mais profunda dos comics das gigantes: Marvel e DC Comics.
Primeiro, vamos filtrar o DataFrame para que sobrem apenas comics destas duas. Depois, vamos calcular através da função pivot table alguns valores médios das duas:
In [20]:
# Vamos agora ver dados somente das duas maiores: Marvel e DC
marvel_dc_comics = comixology_df[(comixology_df.Publisher == 'Marvel') |
(comixology_df.Publisher == 'DC Comics')]
# Primeiro, alguns valores médios de cada uma
marvel_dc_pivot_averages = pd.pivot_table(marvel_dc_comics,
values=['Rating','Original_price','Page Count',
'Price_per_page'],
index=['Publisher'],
aggfunc=[np.mean])
print(marvel_dc_pivot_averages)
Como vemos, a DC possui um preço médio e preço por página menor, enquanto possui uma avaliação média levemente maior. A quantidade média de páginas nos comics da Marvel é um pouco maior. Abaixo, os gráficos de barra representando cada uma destas comparações:
In [21]:
plt.figure(1,figsize=(10, 6))
plt.subplot(221) # Mean original price
y_axis = marvel_dc_pivot_averages['mean']['Original_price']
x_axis = np.arange(len(marvel_dc_pivot_averages['mean']['Original_price']))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4,
tuple(marvel_dc_pivot_averages['mean']['Original_price'].index))
plt.title('Mean Original Price')
plt.tight_layout()
plt.subplot(222) # Mean page count
y_axis = marvel_dc_pivot_averages['mean']['Page Count']
x_axis = np.arange(len(marvel_dc_pivot_averages['mean']['Page Count']))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4,
tuple(marvel_dc_pivot_averages['mean']['Page Count'].index))
plt.title('Mean Page Count')
plt.tight_layout()
plt.subplot(223) # Mean Price Per Page
y_axis = marvel_dc_pivot_averages['mean']['Price_per_page']
x_axis = np.arange(len(marvel_dc_pivot_averages['mean']['Price_per_page']))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4,
tuple(marvel_dc_pivot_averages['mean']['Price_per_page'].index))
plt.title('Mean Price Per Page')
plt.tight_layout()
plt.subplot(224) # Mean Comic Rating
y_axis = marvel_dc_pivot_averages['mean']['Rating']
x_axis = np.arange(len(marvel_dc_pivot_averages['mean']['Rating']))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4,
tuple(marvel_dc_pivot_averages['mean']['Rating'].index))
plt.title('Mean Comic Rating')
plt.tight_layout()
plt.show()
O próximo passo é ver alguns números relativos a quantidade de comics de cada uma. Quantos comics cada uma possui, qual o número de comics bons (avaliação 4 ou 5) e ruins (avaliação 1 ou 2) e sua proporção perante o número total de comics. Para fazer esta análise, vamos meramente fazer alguns filtros e verificar o comprimento do DataFrame após estes filtros. Simples:
In [22]:
# Vamos agora verificar a quantidade de comics de cada uma e fazer uma proporção
# com a quantidade de comics de cada uma com rating maior ou igual a 4. Desta
# forma podemos ver qual delas, proporcionalmente, lança bons comics
marvel_total = len(marvel_dc_comics[marvel_dc_comics['Publisher'] == 'Marvel'])
marvel_4_or_5 = len(marvel_dc_comics[(marvel_dc_comics['Publisher'] == 'Marvel')
& (marvel_dc_comics['Rating'] >= 4)])
marvel_proportion_4_or_5 = marvel_4_or_5 / marvel_total
marvel_1_or_2 = len(marvel_dc_comics[(marvel_dc_comics['Publisher'] == 'Marvel')
& (marvel_dc_comics['Rating'] <= 2)])
marvel_proportion_1_or_2 = marvel_1_or_2 / marvel_total
dc_total = len(marvel_dc_comics[marvel_dc_comics['Publisher'] == 'DC Comics'])
dc_4_or_5 = len(marvel_dc_comics[(marvel_dc_comics['Publisher'] == 'DC Comics')
& (marvel_dc_comics['Rating'] >= 4)])
dc_proportion_4_or_5 = dc_4_or_5 / dc_total
dc_1_or_2 = len(marvel_dc_comics[(marvel_dc_comics['Publisher'] == 'DC Comics')
& (marvel_dc_comics['Rating'] <= 2)])
dc_proportion_1_or_2 = dc_1_or_2 / dc_total
print("\n")
print("Total de Comics Marvel: " + str(marvel_total))
print("Total de Comics Marvel com avaliação maior ou igual a 4: " +
str(marvel_4_or_5))
print("Proporção de Comics Marvel com avaliação maior ou igual a 4: " +
str("{0:.2f}%".format(marvel_proportion_4_or_5 * 100)))
print("Total de Comics Marvel com avaliação menor ou igual a 2: " +
str(marvel_1_or_2))
print("Proporção de Comics Marvel com avaliação menor ou igual a 2: " +
str("{0:.2f}%".format(marvel_proportion_1_or_2 * 100)))
print("\n")
print("Total de Comics DC Comics: " + str(dc_total))
print("Total de Comics DC Comics com avaliação maior ou igual a 4: " +
str(dc_4_or_5))
print("Proporção de Comics DC Comics com avaliação maior ou igual a 4: " +
str("{0:.2f}%".format(dc_proportion_4_or_5 * 100)))
print("Total de Comics DC Comics com avaliação menor ou igual a 2: " +
str(dc_1_or_2))
print("Proporção de Comics DC Comics com avaliação menor ou igual a 2: " +
str("{0:.2f}%".format(dc_proportion_1_or_2 * 100)))
print("\n")
Novamente, aqui, a DC Comics se mostra um pouquinho melhor. Tem uma maior proporção de comics bons e uma menor proporção de comics ruins. Ponto para a DC de novo. Abaixo, o gráfico fazendo as comparações:
In [23]:
plt.figure(2,figsize=(10, 6))
plt.subplot(221) # Total de Comics de cada editora
y_axis = [dc_total, marvel_total]
x_axis = np.arange(len(y_axis))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4, ('DC Comics','Marvel'))
plt.title('Comics Totais')
plt.tight_layout()
plt.subplot(222) # Proporção de Comics com avaliação 4 ou 5
y_axis = [dc_proportion_4_or_5 * 100, marvel_proportion_4_or_5 * 100]
x_axis = np.arange(len(y_axis))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4, ('DC Comics','Marvel'))
plt.title('Proporção de Comics com avaliação 4 ou 5')
plt.tight_layout()
plt.subplot(223) # Proporção de Comics com avaliação 1 ou 2
y_axis = [dc_proportion_1_or_2 * 100, marvel_proportion_1_or_2 * 100]
x_axis = np.arange(len(y_axis))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4, ('DC Comics','Marvel'))
plt.title('Proporção de Comics com avaliação 1 ou 2')
plt.tight_layout()
plt.show()
Apenas como curiosidade, vamos verificar o número de avaliações dadas em comics de cada uma, através de mais uma pivot table:
In [24]:
# Somar a quantidade de avaliações em comics de cada editora
marvel_dc_pivot_sums = pd.pivot_table(marvel_dc_comics,
values=['Ratings_Quantity'],
index=['Publisher'],
aggfunc=[np.sum])
print(marvel_dc_pivot_sums)
Interessante notar que mesmo a Marvel tendo uma quantidade maior de comics, como vimos na tabela anterior, a quantidade de avaliações em comics da DC é bem maior, cerca de 55% a mais. Parece que os fãs dos comics da DC são mais propensos a avaliar os comics na Comixology que os da Marvel.
Nossa próxima avaliação será a de personagens e equipes de heróis / vilões. Primeiramente, vamos criar listas com personagens de cada uma, e igualmente para times. Dividi os personagens entre as Publishers e criei as listas na mão. Deu um trabalhinho, mas nada demais.
In [25]:
main_dc_characters = ['Superman','Batman','Aquaman','Wonder Woman', 'Flash',
'Robin','Arrow', 'Batgirl', 'Bane', 'Harley Queen',
'Poison Ivy', 'Joker','Firestorm','Vixen',
'Martian Manhunter','Zod','Penguin','Lex Luthor',
'Green Lantern','Supergirl','Atom','Cyborg','Hawkgirl',
'Starfire','Jonah Hex','Booster Gold','Black Canary',
'Shazam','Catwoman','Nightwing','Zatanna','Hawkman',
'Power Girl','Rorschach','Doctor Manhattan',
'Blue Beetle','Batwoman','Darkseid','Vandal Savage',
"Ra's Al Ghul",'Riddler','Reverse Flash','Black Adam',
'Deathstroke','Brainiac','Sinestro','Two-Face']
main_marvel_characters = ['Spider-Man','Captain Marvel','Hulk','Thor',
'Iron Man','Luke Cage','Black Widow','Daredevil',
'Captain America','Jessica Jones','Ghost Rider',
'Spider-Woman','Silver Surfer','Beast','Thing',
'Kitty Pride','Doctor Strange','Black Panther',
'Invisible Woman','Nick Fury','Storm','Professor X',
'Cyclops','Jean Grey','Wolverine','Scarlet Witch',
'Gambit','Rogue','X-23','Iceman','She-Hulk',
'Iron Fist','Hawkeye','Quicksilver','Vision',
'Ant-Man','Cable','Bishop','Colossus','Deadpool',
'Human Torch','Mr. Fantastic','Nightcrawler','Nova',
'Psylocke','Punisher','Rocket Raccoon','Groot',
'Star-Lord','War Machine','Gamora','Drax','Venom',
'Carnage','Octopus','Green Goblin','Abomination',
'Enchantress','Sentinel','Viper','Lady Deathstrike',
'Annihilus','Ultron','Galactus','Kang','Bullseye',
'Juggernaut','Sabretooth','Mystique','Kingpin',
'Apocalypse','Thanos','Dark Phoenix','Loki',
'Red Skull','Magneto','Doctor Doom','Ronan']
dc_teams = ['Justice League','Teen Titans','Justice Society','Lantern Corps',
'Legion of Super-Heroes','All-Star Squadron','Suicide Squad',
'Birds of Prey','Gen13', 'The League of Extraordinary Gentlemen',
'Watchmen']
marvel_teams = ['X-Men','Avengers','Fantastic Four','Asgardian Gods','Skrulls',
'S.H.I.E.L.D.','Inhumans','A.I.M.','X-Factor','X-Force',
'Defenders','New Mutants','Brotherhood of Evil Mutants',
'Thunderbolts', 'Alpha Flight','Guardians of the Galaxy',
'Nova Corps','Illuminati']
Agora, vamos passar por cada nome de personagem e time. Primeiramente, vamos definir um DataFrame, e faremos um filtro nos nomes das comics que possuem o nome deste personagem ou time. Depois, vamos extrair algumas informações daí. A quantidade de comics será basicamente o número de linhas do DataFrame, obtido através da função len(). Depois, as médias de avaliação, preço e quantidade de páginas. Cada uma destas informações será salva em um dictionary, que será adicionado a uma lista. No fim, teremos uma lista de dicts para os personagens e uma lista de dicts para os times:
In [26]:
character_row = {}
characters_dicts = []
for character in main_dc_characters:
character_df = comixology_df[(comixology_df['Name'].str.contains(character)) &
(comixology_df['Publisher'] == 'DC Comics')]
character_row['Character_Name'] = character
character_row['Quantity_of_comics'] = len(character_df)
character_row['Average_Rating'] = np.nanmean(character_df['Rating'])
character_row['Average_Price'] = np.nanmean(character_df['Original_price'])
character_row['Average_Pages'] = np.nanmean(character_df['Page Count'])
character_row['Publisher'] = "DC Comics"
characters_dicts.append(character_row)
character_row = {}
for character in main_marvel_characters:
character_df = comixology_df[(comixology_df['Name'].str.contains(character)) &
(comixology_df['Publisher'] == 'Marvel')]
character_row['Character_Name'] = character
character_row['Quantity_of_comics'] = len(character_df)
character_row['Average_Rating'] = np.nanmean(character_df['Rating'])
character_row['Average_Price'] = np.nanmean(character_df['Original_price'])
character_row['Average_Pages'] = np.nanmean(character_df['Page Count'])
character_row['Publisher'] = "Marvel"
characters_dicts.append(character_row)
character_row = {}
characters_df = pd.DataFrame(characters_dicts)
In [27]:
team_row = {}
teams_dicts = []
for team in dc_teams:
team_df = comixology_df[(comixology_df['Name'].str.contains(team)) &
(comixology_df['Publisher'] == 'DC Comics')]
team_row['Team_Name'] = team
team_row['Quantity_of_comics'] = len(team_df)
team_row['Average_Rating'] = np.nanmean(team_df['Rating'])
team_row['Average_Price'] = np.nanmean(team_df['Original_price'])
team_row['Average_Pages'] = np.nanmean(team_df['Page Count'])
team_row['Publisher'] = "DC Comics"
teams_dicts.append(team_row)
team_row = {}
for team in marvel_teams:
team_df = comixology_df[(comixology_df['Name'].str.contains(team)) &
(comixology_df['Publisher'] == 'Marvel')]
team_row['Team_Name'] = team
team_row['Quantity_of_comics'] = len(team_df)
team_row['Average_Rating'] = np.nanmean(team_df['Rating'])
team_row['Average_Price'] = np.nanmean(team_df['Original_price'])
team_row['Average_Pages'] = np.nanmean(team_df['Page Count'])
team_row['Publisher'] = "Marvel"
teams_dicts.append(team_row)
team_row = {}
teams_df = pd.DataFrame(teams_dicts)
Vamos considerar apenas times e personagens que possuam mais de 20 comics onde seu nome está no título do comic.
In [28]:
teams_df = teams_df[teams_df['Quantity_of_comics'] > 20]
characters_df = characters_df[characters_df['Quantity_of_comics'] > 20]
Vamos agora verificar os maiores times e personagens em número de comics e avaliação média. Para os personagens, mesmo considerando aqueles com mais de 20 comics, ainda sobra muita coisa. Desta forma, vamos limitar a quantidade de personagens a 20, para que a lista e o gráfico não fiquem muito extensos. Depois vamos imprimir cada uma das tabelas.
In [29]:
# Limitando a 20 o número de personagens
top_characters_by_quantity = characters_df.sort_values(by='Quantity_of_comics',
ascending=False)[['Character_Name',
'Average_Rating',
'Quantity_of_comics']].head(20)
top_characters_by_rating = characters_df.sort_values(by='Average_Rating',
ascending=False)[['Character_Name',
'Average_Rating',
'Quantity_of_comics']].head(20)
top_teams_by_quantity = teams_df.sort_values(by='Quantity_of_comics',
ascending=False)[['Team_Name',
'Average_Rating',
'Quantity_of_comics']]
top_teams_by_rating = teams_df.sort_values(by='Average_Rating',
ascending=False)[['Team_Name',
'Average_Rating',
'Quantity_of_comics']]
print(top_characters_by_quantity)
Entre os personagens, temos o Batman com o maior número de comics, seguido pelo Homem-Aranha e, bem atrás o Superman completando o top 3. Depois temos uma série de outros heróis famosos, como Capitão América, Homem de Ferro, Wolverine, Flash, entre outros. Aqui, nada de muito surpreendente.
In [30]:
print(top_characters_by_rating)
Aqui temos uma surpresa na liderança. Mesmo com a quantidade de comics não sendo tão grande, acho difícil que alguém previsse que a Mystique seria o personagem com a avaliação média mais alta no meio destes personagens todos, tão mais populares. Nas primeiras posições, outros resultados surpreendentes, com Booster Gold em segundo, Jonah Hex em terceiro, Blue Beetle em quinto. Dos super populares que vimos na lista de cima, temos o Spider-Man, Deadpool e Wonder Woman, já no fim da lista do top 20.
In [31]:
print(top_teams_by_quantity)
Entre os times com mais comics, nada de muito surpreendente também. Os eternos X-Men em primeiro, Avengers em segundo e Justice League em terceiro. Depois, seguem os outros times menos populares.
In [32]:
print(top_teams_by_rating)
Nas avaliações, o top 3 é formado pelo All-Star Squadron, da DC, Fantastic Four e Thunderbolts, da Marvel. Surpreendentemente, X-Men, Avengers e o Suicide Squad (cujo filme está chegando em breve), ficam na parte de baixo da lista.
Abaixo plotamos estas tabelas para ajudar na visualização.
In [33]:
plt.figure(3,figsize=(10, 6))
plt.subplot(121) # Personagem por quantidade de comics
y_axis = top_characters_by_quantity['Quantity_of_comics']
x_axis = np.arange(len(y_axis))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4, tuple(top_characters_by_quantity['Character_Name']),
rotation=90)
plt.title('Personagem por Qtd de Comics')
plt.tight_layout()
plt.subplot(122) # Personagem por avaliação média
y_axis = top_characters_by_rating['Average_Rating']
x_axis = np.arange(len(y_axis))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4, tuple(top_characters_by_rating['Character_Name']),
rotation=90)
plt.title('Personagem por Avaliação Média')
plt.tight_layout()
plt.show()
In [34]:
plt.figure(4,figsize=(10, 6))
plt.subplot(121) # Time por quantidade de comics
y_axis = top_teams_by_quantity['Quantity_of_comics']
x_axis = np.arange(len(y_axis))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4, tuple(top_teams_by_quantity['Team_Name']), rotation=90)
plt.title('Time por quantidade de comics')
plt.tight_layout()
plt.subplot(122) # Time por avaliação média
y_axis = top_teams_by_rating['Average_Rating']
x_axis = np.arange(len(y_axis))
plt.bar(x_axis, y_axis)
plt.xticks(x_axis+0.4, tuple(top_teams_by_rating['Team_Name']), rotation=90)
plt.title('Time por avaliação média')
plt.tight_layout()
plt.show()
Com isto, encerra-se a nossa série de 3 posts sobre análise do site, web scraping e análise de dados de comics digitais, com informações extraídas do site da Comixology. Como nem sempre os dados estão disponíveis de uma forma simples e prática, como um banco de dados ou um dataset em csv, podemos ter que buscar os dados através de web scraping, varrendo links em busca das informações que queremos.
Aqui nesta análise, chegamos a conclusão relativas aos comics presentes no site, na visão de seus usuários. Um resumo das conclusões está na lista abaixo:
E assim terminamos nosso pequeno projeto. Espero que tenham gostado :)
Abraços